﻿using System.Linq.Expressions;

namespace Singer.Middleware.EFCore;

/// <summary>
/// EFCore 仓储基类 接口
/// </summary>
/// <typeparam name="TDbContext">DbContext类型</typeparam>
/// <typeparam name="TEntity">实体类型</typeparam>
public interface IBaseRepository<TDbContext, TEntity>
    where TDbContext : EFCoreDbContext
    where TEntity : class, IEntity
{
    //DDD中，所有数据库操作都应在仓储层。这里DbContext 和 Table 不应公开。（这里方便测试用。实际业务中不应公开）
    TDbContext DbContext { get; }
    DbSet<TEntity> Table { get; }

    void Attach(TEntity entity);
    void Attach(IEnumerable<TEntity> entities);

    void RemoveAttach(TEntity entity);
    void RemoveAttach(IEnumerable<TEntity> entities);

    int SaveChanges();
    Task<int> SaveChangesAsync();

    int Add(TEntity entity, bool saveChanges = true);
    Task<int> AddAsync(TEntity entity, bool saveChanges = true);
    int Add(IEnumerable<TEntity> entities, bool saveChanges = true);
    Task<int> AddAsync(IEnumerable<TEntity> entities, bool saveChanges = true);

    int Update(TEntity entity, bool saveChanges = true);
    Task<int> UpdateAsync(TEntity entity, bool saveChanges = true);
    int Update(IEnumerable<TEntity> entities, bool saveChanges = true);
    Task<int> UpdateAsync(IEnumerable<TEntity> entities, bool saveChanges = true);

    int Delete(TEntity entity, bool saveChanges = true);
    Task<int> DeleteAsync(TEntity entity, bool saveChanges = true);
    int Delete(IEnumerable<TEntity> entities, bool saveChanges = true);
    Task<int> DeleteAsync(IEnumerable<TEntity> entities, bool saveChanges = true);
    int Delete(Expression<Func<TEntity, bool>> expWhere);
    Task<int> DeleteAsync(Expression<Func<TEntity, bool>> expWhere);

    TEntity? Get(Expression<Func<TEntity, bool>>? expWhere = null, bool noTracking = false);
    Task<TEntity?> GetAsync(Expression<Func<TEntity, bool>>? expWhere = null, bool noTracking = false);


    int Count(Expression<Func<TEntity, bool>>? expWhere = null);
    Task<int> CountAsync(Expression<Func<TEntity, bool>>? expWhere = null);

    bool Any(Expression<Func<TEntity, bool>>? expWhere = null);
    Task<bool> AnyAsync(Expression<Func<TEntity, bool>>? expWhere = null);

    T? Max<T>(Expression<Func<TEntity, T>> maxSelector, Expression<Func<TEntity, bool>>? expWhere = null);
    Task<T?> MaxAsync<T>(Expression<Func<TEntity, T>> maxSelector, Expression<Func<TEntity, bool>>? expWhere = null);

    T? Min<T>(Expression<Func<TEntity, T>> minSelector, Expression<Func<TEntity, bool>>? expWhere = null);
    Task<T?> MinAsync<T>(Expression<Func<TEntity, T>> minSelector, Expression<Func<TEntity, bool>>? expWhere = null);

    T? SelectValue<T>(Expression<Func<TEntity, T>> selector, Expression<Func<TEntity, bool>>? expWhere = null);
    Task<T?> SelectValueAsync<T>(Expression<Func<TEntity, T>> selector, Expression<Func<TEntity, bool>>? expWhere = null);

    List<T> SelectValueList<T>(Expression<Func<TEntity, T>> selector, Expression<Func<TEntity, bool>>? expWhere = null);
    Task<List<T>> SelectValueListAsync<T>(Expression<Func<TEntity, T>> selector, Expression<Func<TEntity, bool>>? expWhere = null);

    List<TEntity> List(Expression<Func<TEntity, bool>>? expWhere = null, bool noTracking = false);
    Task<List<TEntity>> ListAsync(Expression<Func<TEntity, bool>>? expWhere = null, bool noTracking = false);
}
